using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Gko.Utils
{
	/// <summary>
	/// Comparer wrapper on method
	/// </summary>
	/// <typeparam name="TValue">The type of the value.</typeparam>
	public class ComparerWrapper<TValue> : IComparer<TValue>
	{
		private readonly Func<TValue, TValue, int> comparer;

		/// <summary>
		/// Initializes a new instance of the <see cref="T:Gko.Utils.ComparerWrapper`1"/> class.
		/// </summary>
		/// <param name="comparer">Function that compares two objects.</param>
		/// <exception cref="ArgumentNullException"><c>comparer</c> is null.</exception>
		public ComparerWrapper(Func<TValue, TValue, int> comparer)
		{
			if (comparer == null) {
				throw new ArgumentNullException("comparer");
			}
			this.comparer = comparer;
		}

		#region IComparer<TValue> Members

		/// <summary>
		/// Compares two objects and returns a value indicating whether one is less than, equal to, or greater than the other.
		/// </summary>
		/// <param name="x">The first object to compare.</param>
		/// <param name="y">The second object to compare.</param>
		/// <returns>
		/// Value Condition Less than zero<paramref name="x"/> is less than <paramref name="y"/>.Zero<paramref name="x"/> equals <paramref name="y"/>.Greater than zero<paramref name="x"/> is greater than <paramref name="y"/>.
		/// </returns>
		public int Compare(TValue x, TValue y)
		{
			return this.comparer(x, y);
		}

		#endregion
	}

	/// <summary>
	/// Static helper functions for creating <see cref="T:Gko.Utils.ComparerWrapper`1"/>
	/// </summary>
	public static class ComparerWrapper
	{
		/// <summary>
		/// Wraps the specified comparer.
		/// </summary>
		/// <typeparam name="TValue">The type of the value.</typeparam>
		/// <param name="comparer">Function that compares two objects.</param>
		/// <returns>New instance of the <see cref="T:Gko.Utils.ComparerWrapper`1"/> class.</returns>
		public static IComparer<TValue> Wrap<TValue>(Func<TValue, TValue, int> comparer)
		{
			return new ComparerWrapper<TValue>(comparer);
		}

		/// <summary>
		/// Wraps comparer based on selector.
		/// </summary>
		/// <typeparam name="TValue">The type of the value.</typeparam>
		/// <typeparam name="TOther">The type of the other.</typeparam>
		/// <param name="selector">The selector.</param>
		/// <returns>New instance of the <see cref="T:Gko.Utils.ComparerWrapper`1"/> class.</returns>
		public static IComparer<TValue> Wrap<TValue, TOther>(Func<TValue, TOther> selector) where TOther : IComparable
		{
			return new ComparerWrapper<TValue>((a, b) => selector(a).CompareTo(selector(b)));
		}
	}
}